home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 June / CHIP Haziran 2001.iso / prog / haziran / 19 / setup.exe / data.z / pbclib.c < prev    next >
C/C++ Source or Header  |  2001-04-11  |  39KB  |  1,216 lines

  1. ////////////////////////////////////////////////////////////////
  2. // File - V3pbclib.c
  3. //
  4. // Library for 'WinDriver for V3 Semiconductor PBC family of devices. 
  5. // The basic idea is to get a handle for the board
  6. // with V3PBC_Open() and use it in the rest of the program
  7. // when calling WD functions.  Call V3PBC_Close() when done.
  8. // 
  9. ////////////////////////////////////////////////////////////////
  10.  
  11. #include "../../include/windrvr.h"
  12. #include "../../include/windrvr_int_thread.h"
  13. #include "pbclib.h"
  14. #include <stdio.h>
  15.  
  16. // this string is set to an error message, if one occurs
  17. CHAR V3PBC_ErrorString[1024];
  18.  
  19. // internal function used by V3PBC_Open()
  20. BOOL V3PBC_DetectCardElements(V3PBCHANDLE hV3);
  21.  
  22. // internal function for setting remap base address
  23. void V3PBC_SetRemapBase0(V3PBCHANDLE hV3, DWORD dwLocalAddr);
  24.  
  25. // internal implementation of active delay
  26. void V3PBC_SleepMicro(V3PBCHANDLE hV3, DWORD nMicro);
  27.  
  28. // internal functions used for EEPROM read/write
  29. BOOL I2C_StartSlave(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit);
  30. BOOL I2C_PollAckStart(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit);
  31. BOOL I2C_Write8(V3PBCHANDLE hV3,BYTE bData);
  32. BYTE I2C_Read8(V3PBCHANDLE hV3);
  33.  
  34. void I2C_Stop(V3PBCHANDLE hV3);
  35. void I2C_NoAck(V3PBCHANDLE hV3);
  36. void I2C_Ack(V3PBCHANDLE hV3);
  37. BYTE I2C_SDAIn(V3PBCHANDLE hV3);
  38. void I2C_SDA(V3PBCHANDLE hV3, BOOL fHigh);
  39. void I2C_SCL(V3PBCHANDLE hV3, BOOL fHigh);
  40. void I2C_Lock(V3PBCHANDLE hV3);
  41. void I2C_UnLock(V3PBCHANDLE hV3);
  42. void I2C_Delay(V3PBCHANDLE hV3);
  43.  
  44.  
  45. //////////////////////////////////////////////////////////////////////////////
  46. // Card Detection/Init
  47. //////////////////////////////////////////////////////////////////////////////
  48.  
  49. DWORD V3PBC_CountCards (DWORD dwVendorID, DWORD dwDeviceID)
  50. {
  51.     WD_VERSION ver;
  52.     WD_PCI_SCAN_CARDS pciScan;
  53.     HANDLE hWD = INVALID_HANDLE_VALUE;
  54.  
  55.     V3PBC_ErrorString[0] = '\0';
  56.     hWD = WD_Open();
  57.     // check if handle valid & version OK
  58.     if (hWD==INVALID_HANDLE_VALUE) 
  59.     {
  60.         sprintf( V3PBC_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
  61.         return 0;
  62.     }
  63.  
  64.     BZERO(ver);
  65.     WD_Version(hWD,&ver);
  66.     if (ver.dwVer<WD_VER) 
  67.     {
  68.         sprintf( V3PBC_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
  69.         WD_Close (hWD);
  70.         return 0;
  71.     }
  72.  
  73.     BZERO(pciScan);
  74.     pciScan.searchId.dwVendorId = dwVendorID;
  75.     pciScan.searchId.dwDeviceId = dwDeviceID;
  76.     WD_PciScanCards (hWD, &pciScan);
  77.     WD_Close (hWD);
  78.     if (pciScan.dwCards==0)
  79.         sprintf( V3PBC_ErrorString, "no cards found\n");
  80.     return pciScan.dwCards;
  81. }
  82.  
  83.  
  84. BOOL V3PBC_Open (V3PBCHANDLE *phV3, DWORD dwVendorID, DWORD dwDeviceID, DWORD nCardNum, DWORD dwOptions)
  85. {
  86.     V3PBCHANDLE hV3 = (V3PBCHANDLE) malloc (sizeof (V3PBC_STRUCT));
  87.  
  88.     WD_VERSION ver;
  89.     WD_PCI_SCAN_CARDS pciScan;
  90.     WD_PCI_CARD_INFO pciCardInfo;
  91.  
  92.     *phV3 = NULL;
  93.     V3PBC_ErrorString[0] = '\0';
  94.     BZERO(*hV3);
  95.  
  96.     hV3->cardReg.hCard = 0;
  97.     hV3->hWD = WD_Open();
  98.  
  99.     // check if handle valid & version OK
  100.     if (hV3->hWD==INVALID_HANDLE_VALUE) 
  101.     {
  102.         sprintf( V3PBC_ErrorString, "Failed opening " WD_PROD_NAME " device\n");
  103.         goto Exit;
  104.     }
  105.  
  106.     BZERO(ver);
  107.     WD_Version(hV3->hWD,&ver);
  108.     if (ver.dwVer<WD_VER) 
  109.     {
  110.         sprintf( V3PBC_ErrorString, "Incorrect " WD_PROD_NAME " version\n");
  111.         goto Exit;
  112.     }
  113.  
  114.     pciScan.searchId.dwVendorId = dwVendorID;
  115.     pciScan.searchId.dwDeviceId = dwDeviceID;
  116.     WD_PciScanCards (hV3->hWD, &pciScan);
  117.     if (pciScan.dwCards==0) // Found at least one card
  118.     {
  119.         sprintf( V3PBC_ErrorString, "Could not find PCI card\n");
  120.         goto Exit;
  121.     }
  122.     if (pciScan.dwCards<=nCardNum)
  123.     {
  124.         sprintf( V3PBC_ErrorString, "Card out of range of available cards\n");
  125.         goto Exit;
  126.     }
  127.  
  128.     BZERO(pciCardInfo);
  129.     pciCardInfo.pciSlot = pciScan.cardSlot[nCardNum];
  130.     WD_PciGetCardInfo (hV3->hWD, &pciCardInfo);
  131.     hV3->pciSlot = pciCardInfo.pciSlot;
  132.     hV3->cardReg.Card = pciCardInfo.Card;
  133.  
  134.     hV3->fUseInt = (dwOptions & V3PBC_OPEN_USE_INT) ? TRUE : FALSE;
  135.     if (!hV3->fUseInt)
  136.     {
  137.         DWORD i;
  138.         // Remove interrupt item if not needed
  139.         for (i=0; i<hV3->cardReg.Card.dwItems; i++)
  140.         {
  141.             WD_ITEMS *pItem = &hV3->cardReg.Card.Item[i];
  142.             if (pItem->item==ITEM_INTERRUPT)
  143.                 pItem->item = ITEM_NONE;
  144.         }
  145.     }
  146.     else
  147.     {
  148.         DWORD i;
  149.         // make interrupt resource sharable
  150.         for (i=0; i<hV3->cardReg.Card.dwItems; i++)
  151.         {
  152.             WD_ITEMS *pItem = &hV3->cardReg.Card.Item[i];
  153.             if (pItem->item==ITEM_INTERRUPT)
  154.                 pItem->fNotSharable = FALSE;
  155.         }
  156.     }
  157.  
  158.     hV3->cardReg.fCheckLockOnly = FALSE;
  159.     WD_CardRegister (hV3->hWD, &hV3->cardReg);
  160.     if (hV3->cardReg.hCard==0)
  161.     {
  162.         sprintf ( V3PBC_ErrorString, "Failed locking device\n");
  163.         goto Exit;
  164.     }
  165.  
  166.     if (!V3PBC_DetectCardElements(hV3))
  167.     {
  168.         sprintf ( V3PBC_ErrorString, "Card does not have all items expected for V3 PBC\n");
  169.         goto Exit;
  170.     }
  171.  
  172.     hV3->dwReg_PCI_MAP0 = V3PBC_ReadRegDWord (hV3, V3PBC_PCI_MAP0);
  173.  
  174.     // Open finished OK
  175.     *phV3 = hV3;
  176.     return TRUE;
  177.  
  178. Exit:
  179.     // Error durin Open
  180.     if (hV3->cardReg.hCard) 
  181.         WD_CardUnregister(hV3->hWD, &hV3->cardReg);
  182.     if (hV3->hWD!=INVALID_HANDLE_VALUE)
  183.         WD_Close(hV3->hWD);
  184.     free (hV3);
  185.     return FALSE;
  186. }
  187.  
  188. DWORD V3PBC_ReadPCIReg(V3PBCHANDLE hV3, DWORD dwReg)
  189. {
  190.     WD_PCI_CONFIG_DUMP pciCnf;
  191.     DWORD dwVal;
  192.  
  193.     BZERO(pciCnf);
  194.     pciCnf.pciSlot = hV3->pciSlot;
  195.     pciCnf.pBuffer = &dwVal;
  196.     pciCnf.dwOffset = dwReg;
  197.     pciCnf.dwBytes = 4;
  198.     pciCnf.fIsRead = TRUE;
  199.     WD_PciConfigDump(hV3->hWD,&pciCnf);
  200.     return dwVal;
  201. }
  202.  
  203. void V3PBC_WritePCIReg(V3PBCHANDLE hV3, DWORD dwReg, DWORD dwData)
  204. {
  205.     WD_PCI_CONFIG_DUMP pciCnf;
  206.  
  207.     BZERO (pciCnf);
  208.     pciCnf.pciSlot = hV3->pciSlot;
  209.     pciCnf.pBuffer = &dwData;
  210.     pciCnf.dwOffset = dwReg;
  211.     pciCnf.dwBytes = 4;
  212.     pciCnf.fIsRead = FALSE;
  213.     WD_PciConfigDump(hV3->hWD,&pciCnf);
  214. }
  215.  
  216. BOOL V3PBC_DetectCardElements(V3PBCHANDLE hV3)
  217. {
  218.     DWORD i;
  219.     DWORD ad_sp;
  220.     DWORD RegisterMask;
  221.  
  222.     memset (&hV3->Int, 0, sizeof (hV3->Int));
  223.     memset (hV3->addrDesc, 0, sizeof (hV3->addrDesc));
  224.  
  225.     for (i=0; i<hV3->cardReg.Card.dwItems; i++)
  226.     {
  227.         WD_ITEMS *pItem = &hV3->cardReg.Card.Item[i];
  228.  
  229.         switch (pItem->item)
  230.         {
  231.         case ITEM_MEMORY:
  232.         case ITEM_IO:
  233.             {
  234.                 DWORD dwBytes;
  235.                 DWORD dwAddr;
  236.                 DWORD dwAddrDirect = 0;
  237.                 DWORD dwPhysAddr;
  238.                 BOOL fIsMemory;
  239.                 if (pItem->item==ITEM_MEMORY)
  240.                 {
  241.                     dwBytes = pItem->I.Mem.dwBytes;
  242.                     dwAddr = pItem->I.Mem.dwTransAddr;
  243.                     dwAddrDirect = pItem->I.Mem.dwUserDirectAddr;
  244.                     dwPhysAddr = pItem->I.Mem.dwPhysicalAddr;
  245.                     fIsMemory = TRUE;
  246.                 }
  247.                 else 
  248.                 {
  249.                     dwBytes = pItem->I.IO.dwBytes;
  250.                     dwAddr = pItem->I.IO.dwAddr;
  251.                     dwPhysAddr = dwAddr & 0xffff;
  252.                     fIsMemory = FALSE;
  253.                 }
  254.  
  255.                 for (ad_sp=V3PBC_ADDR_IO_BASE; ad_sp<=V3PBC_ADDR_ROM; ad_sp++)
  256.                 {
  257.                     DWORD dwPCIAddr;
  258.                     DWORD dwPCIReg;
  259.                     DWORD dwApertureSize;
  260.  
  261.                     if (hV3->addrDesc[ad_sp].dwAddr) continue;
  262.                     if (ad_sp==V3PBC_ADDR_IO_BASE) dwPCIReg = V3PBC_PCI_IO_BASE;
  263.                     else if (ad_sp==V3PBC_ADDR_BASE0) dwPCIReg = V3PBC_PCI_BASE0;
  264.                     else if (ad_sp==V3PBC_ADDR_BASE1) dwPCIReg = V3PBC_PCI_BASE1;
  265.                     else if (ad_sp==V3PBC_ADDR_ROM) dwPCIReg = V3PBC_PCI_ROM;
  266.                     else continue;
  267.  
  268.                     dwPCIAddr = V3PBC_ReadPCIReg(hV3, dwPCIReg);
  269.                     if (ad_sp==V3PBC_ADDR_IO_BASE)
  270.                     {
  271.                         //
  272.                         // The V3PBC_PCI_IO_BASE register uses address lines 31-8 for decoding. 
  273.                         //
  274.                         RegisterMask = (DWORD) 0xffffff00;
  275.                     }
  276.                     else
  277.                     {
  278.                         dwApertureSize = (dwPCIAddr & 0x000000f0) >> 4;
  279.                         if (dwPCIAddr & 1)
  280.                         {
  281.                             //
  282.                             // The aperture defines an I/O region
  283.                             // Valid I/O values are from 4 to 7 use address lines 31-8
  284.                             //
  285.                             dwApertureSize -= 4;
  286.                             RegisterMask = (DWORD) 0xffffff00;
  287.                         }
  288.                         else
  289.                         {
  290.                             //
  291.                             // The aperture defines a memory region use address lines 31-20
  292.                             //
  293.                             RegisterMask = (DWORD) 0xfff00000;
  294.                         }    
  295.  
  296.                         //
  297.                         // Reduce mask size base on aperture size
  298.                         //
  299.                         while(dwApertureSize != 0) 
  300.                         {
  301.                             RegisterMask <<=1;    
  302.                             dwApertureSize--;
  303.                         }
  304.                     }
  305.  
  306.  
  307.                     if (dwPCIAddr & 1)
  308.                     {
  309.                         if (fIsMemory) continue;
  310.                         dwPCIAddr &= RegisterMask;
  311.                     }
  312.                     else
  313.                     {
  314.                         if (!fIsMemory) continue;
  315.                         dwPCIAddr &= RegisterMask;
  316.                     }
  317.                     //
  318.                     // Found Item description that matches PBC aperture settings, so break for loop 
  319.                     //
  320.                     if (dwPCIAddr==dwPhysAddr)
  321.                         break;
  322.                 }
  323.                 if (ad_sp<=V3PBC_ADDR_ROM)
  324.                 {
  325.                     DWORD j;
  326.                     hV3->addrDesc[ad_sp].dwBytes = dwBytes;
  327.                     hV3->addrDesc[ad_sp].dwAddr = dwAddr;
  328.                     hV3->addrDesc[ad_sp].dwAddrDirect = dwAddrDirect;
  329.                     hV3->addrDesc[ad_sp].fIsMemory = fIsMemory;
  330.                     hV3->addrDesc[ad_sp].dwMask = 0;
  331.                     for (j=1; j<hV3->addrDesc[ad_sp].dwBytes && j!=0x80000000; j *= 2)
  332.                     {
  333.                         hV3->addrDesc[ad_sp].dwMask = 
  334.                             (hV3->addrDesc[ad_sp].dwMask << 1) | 1;
  335.                     }
  336.                 }
  337.             }
  338.             break;
  339.         case ITEM_INTERRUPT:
  340.             if (hV3->Int.Int.hInterrupt) return FALSE;
  341.             hV3->Int.Int.hInterrupt = pItem->I.Int.hInterrupt;
  342.             break;
  343.         }
  344.     }
  345.  
  346.     // check that all the items needed were found
  347.     // check if interrupt found
  348.     if (hV3->fUseInt && !hV3->Int.Int.hInterrupt) 
  349.     {
  350.         return FALSE;
  351.     }
  352.  
  353.     // check that the registers space was found
  354.     if (!V3PBC_IsAddrSpaceActive(hV3, V3PBC_ADDR_IO_BASE)
  355.             || hV3->addrDesc[V3PBC_ADDR_IO_BASE].dwBytes!=V3PBC_RANGE_REG)
  356.         return FALSE;
  357.  
  358.     // check that at least one memory space was found
  359.     for (i = V3PBC_ADDR_IO_BASE; i<=V3PBC_ADDR_ROM; i++)
  360.         if (V3PBC_IsAddrSpaceActive(hV3, i)) break;
  361.     if (i>V3PBC_ADDR_ROM) return FALSE;
  362.  
  363.     return TRUE;
  364. }
  365.  
  366. void V3PBC_Close(V3PBCHANDLE hV3)
  367. {
  368.     // disable interrupts
  369.     if (V3PBC_IntIsEnabled(hV3))
  370.         V3PBC_IntDisable(hV3);
  371.  
  372.     // unregister card
  373.     if (hV3->cardReg.hCard) 
  374.         WD_CardUnregister(hV3->hWD, &hV3->cardReg);
  375.  
  376.     // close WinDriver
  377.     WD_Close(hV3->hWD);
  378.  
  379.     free (hV3);
  380. }
  381.  
  382. BOOL V3PBC_IsAddrSpaceActive(V3PBCHANDLE hV3, V3PBC_ADDR addrSpace)
  383. {
  384.     return hV3->addrDesc[addrSpace].dwAddr!=0;
  385. }
  386.  
  387. DWORD V3PBC_GetRevision(V3PBCHANDLE hV3)
  388. {
  389.     DWORD dwRev = V3PBC_ReadRegDWord(hV3, V3PBC_PCI_CC_REV);
  390.     return dwRev & 0xf;
  391. }
  392.  
  393. //////////////////////////////////////////////////////////////////////////////
  394. // Access Registers range
  395. //////////////////////////////////////////////////////////////////////////////
  396.  
  397. void V3PBC_WriteRegDWord (V3PBCHANDLE hV3, DWORD dwReg, DWORD dwData)
  398. {
  399.     V3PBC_WriteSpaceDWord (hV3, V3PBC_ADDR_IO_BASE, dwReg, dwData);
  400. }
  401.  
  402. DWORD V3PBC_ReadRegDWord (V3PBCHANDLE hV3, DWORD dwReg)
  403. {
  404.     return V3PBC_ReadSpaceDWord(hV3, V3PBC_ADDR_IO_BASE, dwReg);
  405. }
  406.  
  407. void V3PBC_WriteRegWord (V3PBCHANDLE hV3, DWORD dwReg, WORD wData)
  408. {
  409.     V3PBC_WriteSpaceWord (hV3, V3PBC_ADDR_IO_BASE, dwReg, wData);
  410. }
  411.  
  412. WORD V3PBC_ReadRegWord (V3PBCHANDLE hV3, DWORD dwReg)
  413. {
  414.     return V3PBC_ReadSpaceWord(hV3, V3PBC_ADDR_IO_BASE, dwReg);
  415. }
  416.  
  417. void V3PBC_WriteRegByte (V3PBCHANDLE hV3, DWORD dwReg, BYTE bData)
  418. {
  419.     V3PBC_WriteSpaceByte (hV3, V3PBC_ADDR_IO_BASE, dwReg, bData);
  420. }
  421.  
  422. BYTE V3PBC_ReadRegByte (V3PBCHANDLE hV3, DWORD dwReg)
  423. {
  424.     return V3PBC_ReadSpaceByte(hV3, V3PBC_ADDR_IO_BASE, dwReg);
  425. }
  426.  
  427. //////////////////////////////////////////////////////////////////////////////
  428. // Access Local range
  429. //////////////////////////////////////////////////////////////////////////////
  430.  
  431. void V3PBC_SetRemapBase0(V3PBCHANDLE hV3, DWORD dwLocalAddr)
  432. {
  433.     DWORD dwMapRegValue = hV3->dwReg_PCI_MAP0; 
  434.     dwMapRegValue |= (~hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask) & dwLocalAddr;
  435.     V3PBC_WriteRegDWord( hV3, V3PBC_PCI_MAP0, dwMapRegValue);
  436. }
  437.  
  438. void V3PBC_WriteDWord (V3PBCHANDLE hV3, DWORD dwLocalAddr, DWORD dwData)
  439. {
  440.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  441.     V3PBC_WriteSpaceDWord (hV3, V3PBC_ADDR_BASE0, 
  442.         hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, dwData);
  443. }
  444.  
  445. DWORD V3PBC_ReadDWord (V3PBCHANDLE hV3, DWORD dwLocalAddr)
  446. {
  447.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  448.     return V3PBC_ReadSpaceDWord(hV3, V3PBC_ADDR_BASE0, 
  449.         hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr);
  450. }
  451.  
  452. void V3PBC_WriteWord (V3PBCHANDLE hV3, DWORD dwLocalAddr, WORD wData)
  453. {
  454.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  455.     V3PBC_WriteSpaceWord (hV3, V3PBC_ADDR_BASE0, 
  456.         hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, wData);
  457. }
  458.  
  459. WORD V3PBC_ReadWord (V3PBCHANDLE hV3, DWORD dwLocalAddr)
  460. {
  461.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  462.     return V3PBC_ReadSpaceWord(hV3, V3PBC_ADDR_BASE0, 
  463.         hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr);
  464. }
  465.  
  466. void V3PBC_WriteByte (V3PBCHANDLE hV3, DWORD dwLocalAddr, BYTE bData)
  467. {
  468.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  469.     V3PBC_WriteSpaceByte (hV3, V3PBC_ADDR_BASE0, 
  470.         hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, bData);
  471. }
  472.  
  473. BYTE V3PBC_ReadByte (V3PBCHANDLE hV3, DWORD dwLocalAddr)
  474. {
  475.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  476.     return V3PBC_ReadSpaceByte(hV3, V3PBC_ADDR_BASE0, 
  477.         hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr);
  478. }
  479.  
  480. void V3PBC_ReadBlock (V3PBCHANDLE hV3, DWORD dwLocalAddr, PVOID buf, DWORD dwBytes)
  481. {
  482.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  483.     V3PBC_ReadSpaceBlock(hV3, hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, 
  484.         buf, dwBytes, V3PBC_ADDR_BASE0);
  485. }
  486.  
  487. void V3PBC_WriteBlock (V3PBCHANDLE hV3, DWORD dwLocalAddr, PVOID buf, DWORD dwBytes)
  488. {
  489.     V3PBC_SetRemapBase0(hV3, dwLocalAddr);
  490.     V3PBC_WriteSpaceBlock(hV3, hV3->addrDesc[V3PBC_ADDR_BASE0].dwMask & dwLocalAddr, 
  491.         buf, dwBytes, V3PBC_ADDR_BASE0);
  492. }
  493.  
  494. //////////////////////////////////////////////////////////////////////////////
  495. // Access Address space (low-level functions)
  496. //////////////////////////////////////////////////////////////////////////////
  497.  
  498. // Note: addrSpace is a base address register
  499. BYTE V3PBC_ReadSpaceByte (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset)
  500. {
  501.     if (hV3->addrDesc[addrSpace].fIsMemory)
  502.     {
  503.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect + 
  504.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  505.         BYTE *pByte = (BYTE *) dwAddr;
  506.         return *pByte;
  507.     }
  508.     else
  509.     {
  510.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr + 
  511.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  512.         WD_TRANSFER trans;
  513.         BZERO(trans);
  514.         trans.cmdTrans = RP_BYTE;
  515.         trans.dwPort = dwAddr;
  516.         WD_Transfer (hV3->hWD, &trans);
  517.         return trans.Data.Byte;
  518.     }
  519. }
  520.  
  521. void V3PBC_WriteSpaceByte (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, BYTE data)
  522. {
  523.     if (hV3->addrDesc[addrSpace].fIsMemory)
  524.     {
  525.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect + 
  526.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  527.         BYTE *pByte = (BYTE *) dwAddr;
  528.         *pByte = data;
  529.     }
  530.     else
  531.     {
  532.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr + 
  533.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  534.         WD_TRANSFER trans;
  535.         BZERO(trans);
  536.         trans.cmdTrans = WP_BYTE;
  537.         trans.dwPort = dwAddr;
  538.         trans.Data.Byte = data;
  539.         WD_Transfer (hV3->hWD, &trans);
  540.     }
  541. }
  542.  
  543. WORD V3PBC_ReadSpaceWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset)
  544. {
  545.     if (hV3->addrDesc[addrSpace].fIsMemory)
  546.     {
  547.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect + 
  548.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  549.         WORD *pWord = (WORD *) dwAddr;
  550.         return *pWord;
  551.     }
  552.     else
  553.     {
  554.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr + 
  555.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  556.         WD_TRANSFER trans;
  557.         BZERO(trans);
  558.         trans.cmdTrans = RP_WORD;
  559.         trans.dwPort = dwAddr;
  560.         WD_Transfer (hV3->hWD, &trans);
  561.         return trans.Data.Word;
  562.     }
  563. }
  564.  
  565. void V3PBC_WriteSpaceWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, WORD data)
  566. {
  567.     if (hV3->addrDesc[addrSpace].fIsMemory)
  568.     {
  569.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect + 
  570.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  571.         WORD *pWord = (WORD *) dwAddr;
  572.         *pWord = data;
  573.     }
  574.     else
  575.     {
  576.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr + 
  577.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  578.         WD_TRANSFER trans;
  579.         BZERO(trans);
  580.         trans.cmdTrans = WP_WORD;
  581.         trans.dwPort = dwAddr;
  582.         trans.Data.Word = data;
  583.         WD_Transfer (hV3->hWD, &trans);
  584.     }
  585. }
  586.  
  587. DWORD V3PBC_ReadSpaceDWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset)
  588. {
  589.     if (hV3->addrDesc[addrSpace].fIsMemory)
  590.     {
  591.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect + 
  592.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  593.         DWORD *pDword = (DWORD *) dwAddr;
  594.         return *pDword;
  595.     }
  596.     else
  597.     {
  598.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr + 
  599.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  600.         WD_TRANSFER trans;
  601.         BZERO(trans);
  602.         trans.cmdTrans = RP_DWORD;
  603.         trans.dwPort = dwAddr;
  604.         WD_Transfer (hV3->hWD, &trans);
  605.         return trans.Data.Dword;
  606.     }
  607. }
  608.  
  609. void V3PBC_WriteSpaceDWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, DWORD data)
  610. {
  611.     if (hV3->addrDesc[addrSpace].fIsMemory)
  612.     {
  613.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddrDirect + 
  614.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  615.         DWORD *pDword = (DWORD *) dwAddr;
  616.         *pDword = data;
  617.     }
  618.     else
  619.     {
  620.         DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr + 
  621.             (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  622.         WD_TRANSFER trans;
  623.         BZERO(trans);
  624.         trans.cmdTrans = WP_DWORD;
  625.         trans.dwPort = dwAddr;
  626.         trans.Data.Dword = data;
  627.         WD_Transfer (hV3->hWD, &trans);
  628.     }
  629. }
  630.  
  631. void V3PBC_ReadWriteSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf, 
  632.                     DWORD dwBytes, BOOL fIsRead, V3PBC_ADDR addrSpace, V3PBC_MODE mode)
  633. {
  634.     WD_TRANSFER trans;
  635.     DWORD dwAddr = hV3->addrDesc[addrSpace].dwAddr +
  636.         (hV3->addrDesc[addrSpace].dwMask & dwOffset);
  637.  
  638.     BZERO(trans);
  639.     
  640.     if (hV3->addrDesc[addrSpace].fIsMemory) 
  641.     {
  642.         if (fIsRead) 
  643.         {
  644.             if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = RM_SBYTE;
  645.             else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = RM_SWORD;
  646.             else trans.cmdTrans = RM_SDWORD;
  647.         }
  648.         else 
  649.         {
  650.             if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = WM_SBYTE;
  651.             else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = WM_SWORD;
  652.             else trans.cmdTrans = WM_SDWORD;
  653.         }
  654.     }
  655.     else 
  656.     {
  657.         if (fIsRead) 
  658.         {
  659.             if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = RP_SBYTE;
  660.             else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = RP_SWORD;
  661.             else trans.cmdTrans = RP_SDWORD;
  662.         }
  663.         else 
  664.         {
  665.             if (mode==V3PBC_MODE_BYTE) trans.cmdTrans = WP_SBYTE;
  666.             else if (mode==V3PBC_MODE_WORD) trans.cmdTrans = WP_SWORD;
  667.             else trans.cmdTrans = WP_SDWORD;
  668.         }
  669.     }
  670.     trans.dwPort = dwAddr;
  671.     trans.fAutoinc = TRUE;
  672.     trans.dwBytes = dwBytes;
  673.     trans.dwOptions = 0;
  674.     trans.Data.pBuffer = buf;
  675.     WD_Transfer (hV3->hWD, &trans);
  676. }
  677.  
  678. void V3PBC_ReadSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf, 
  679.                     DWORD dwBytes, V3PBC_ADDR addrSpace)
  680. {
  681.     V3PBC_ReadWriteSpaceBlock (hV3, dwOffset, buf, dwBytes, TRUE, addrSpace, V3PBC_MODE_DWORD);
  682. }
  683.  
  684. void V3PBC_WriteSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf, 
  685.                      DWORD dwBytes, V3PBC_ADDR addrSpace)
  686. {
  687.     V3PBC_ReadWriteSpaceBlock (hV3, dwOffset, buf, dwBytes, FALSE, addrSpace, V3PBC_MODE_DWORD);
  688. }
  689.  
  690.  
  691. //////////////////////////////////////////////////////////////////////////////
  692. // Interrupts
  693. //////////////////////////////////////////////////////////////////////////////
  694.  
  695. BOOL V3PBC_IntIsEnabled (V3PBCHANDLE hV3)
  696. {
  697.     if (!hV3->fUseInt) return FALSE;
  698.     if (!hV3->Int.hThread) return FALSE;
  699.     return TRUE;
  700. }
  701.  
  702. VOID V3PBC_IntHandler (PVOID pData)
  703. {
  704.     V3PBCHANDLE hV3 = (V3PBCHANDLE) pData;
  705.     V3PBC_INT_RESULT intResult;
  706.  
  707.     intResult.dwCounter = hV3->Int.Int.dwCounter;
  708.     intResult.dwLost = hV3->Int.Int.dwLost;
  709.     intResult.fStopped = hV3->Int.Int.fStopped;
  710.     intResult.dwStatusReg = hV3->Int.Trans[0].Data.Dword;
  711.     hV3->Int.funcIntHandler(hV3, &intResult);
  712. }
  713.  
  714. BOOL V3PBC_IntEnable (V3PBCHANDLE hV3, V3PBC_INT_HANDLER funcIntHandler)
  715. {
  716.     DWORD dwIntStatus;
  717.     DWORD dwAddr;
  718.  
  719.     if (!hV3->fUseInt) return FALSE;
  720.     // check if interrupt is already enabled
  721.     if (hV3->Int.hThread) return FALSE;
  722.  
  723.     dwIntStatus = V3PBC_ReadRegDWord (hV3, V3PBC_PCI_BPARM);
  724.  
  725.     BZERO(hV3->Int.Trans);
  726.     // This is a samlpe of handling interrupts:
  727.     // Two transfer commands are issued. First the value of the interrrupt control/status
  728.     // register is read. Then, a value of ZERO is written.
  729.     // This will cancel interrupts after the first interrupt occurs.
  730.     // When using interrupts, this section will have to change:
  731.     // you must put transfer commands to CANCEL the source of the interrupt, otherwise, the 
  732.     // PC will hang when an interrupt occurs!
  733.     dwAddr = hV3->addrDesc[V3PBC_ADDR_IO_BASE].dwAddr + V3PBC_PCI_BPARM;
  734.     hV3->Int.Trans[0].cmdTrans = hV3->addrDesc[V3PBC_ADDR_IO_BASE].fIsMemory ? RM_DWORD : RP_DWORD;
  735.     hV3->Int.Trans[0].dwPort = dwAddr;
  736.     hV3->Int.Trans[1].cmdTrans = hV3->addrDesc[V3PBC_ADDR_IO_BASE].fIsMemory ? WM_DWORD : WP_DWORD;
  737.     hV3->Int.Trans[1].dwPort = dwAddr;
  738.     hV3->Int.Trans[1].Data.Dword = dwIntStatus & ~BIT8; // put here the data to write to the control register
  739.     hV3->Int.Int.dwCmds = 2; 
  740.     hV3->Int.Int.Cmd = hV3->Int.Trans;
  741.     hV3->Int.Int.dwOptions |= INTERRUPT_CMD_COPY;
  742.  
  743.     // this calls WD_IntEnable() and creates an interrupt handler thread
  744.     hV3->Int.funcIntHandler = funcIntHandler;
  745.     if (!InterruptThreadEnable(&hV3->Int.hThread, hV3->hWD, &hV3->Int.Int, V3PBC_IntHandler, (PVOID) hV3))
  746.         return FALSE;
  747.  
  748.     // this enables interrupts
  749.     // Enable INTA to interrupt the PCI bus
  750.     V3PBC_WriteRegDWord (hV3, V3PBC_PCI_BPARM, dwIntStatus | BIT8);
  751.  
  752.     return TRUE;
  753. }
  754.  
  755. void V3PBC_IntDisable (V3PBCHANDLE hV3)
  756. {
  757.     DWORD dwIntStatus;
  758.  
  759.     if (!hV3->fUseInt) return;
  760.     if (!hV3->Int.hThread) return;
  761.  
  762.     // this disables interrupts
  763.     // Disable interrupt assumes INTA was enabled
  764.     dwIntStatus = V3PBC_ReadRegDWord (hV3, V3PBC_PCI_BPARM);
  765.     V3PBC_WriteRegDWord (hV3, V3PBC_PCI_BPARM, dwIntStatus & ~BIT8);
  766.  
  767.     // this calls WD_IntDisable()
  768.     InterruptThreadDisable(hV3->Int.hThread);
  769.  
  770.     hV3->Int.hThread = NULL;
  771. }
  772.  
  773.  
  774. //////////////////////////////////////////////////////////////////////////////
  775. // DMA
  776. //////////////////////////////////////////////////////////////////////////////
  777.  
  778. BOOL V3PBC_DMAOpen(V3PBCHANDLE hV3, WD_DMA *pDMA, DWORD dwBytes)
  779. {
  780.     V3PBC_ErrorString[0] = '\0';
  781.     BZERO(*pDMA);
  782.     pDMA->pUserAddr = NULL; // the kernel will allocate the buffer
  783.     pDMA->dwBytes = dwBytes; // size of buffer to allocate
  784.     pDMA->dwOptions = DMA_KERNEL_BUFFER_ALLOC; 
  785.     WD_DMALock (hV3->hWD, pDMA);
  786.     if (!pDMA->hDma) 
  787.     {
  788.         sprintf (V3PBC_ErrorString, "Failed allocating the buffer!\n");
  789.         return FALSE;
  790.     }
  791.  
  792.     return TRUE;
  793. }
  794.  
  795. void V3PBC_DMAClose(V3PBCHANDLE hV3, WD_DMA *pDMA)
  796. {
  797.     WD_DMAUnlock (hV3->hWD, pDMA);
  798. }
  799.  
  800. BOOL V3PBC_DMAStart(V3PBCHANDLE hV3, V3_DMA_CHANNEL dmaChannel, WD_DMA *pDMA, BOOL fRead,
  801.     BOOL fBlocking, DWORD dwBytes, DWORD dwOffset, DWORD dwLocalAddr)
  802. {
  803.     DWORD dwDMACSR0;
  804.     DWORD dwChannelOffset = dmaChannel*0x10;
  805.  
  806.     V3PBC_WriteRegDWord(hV3, V3PBC_DMA_LOCAL_ADDR0 + dwChannelOffset, dwLocalAddr);
  807.     V3PBC_WriteRegDWord(hV3, V3PBC_DMA_PCI_ADDR0 + dwChannelOffset,
  808.         (DWORD) pDMA->Page[0].pPhysicalAddr + dwOffset);
  809.     // BIT[0-23] count is in DWORDS divide by 4
  810.     // BIT24 - initiate transfer (write)
  811.     // BIT24 - DMA transfer busy (read)
  812.     // BIT28 - transfer direction
  813.     // Preserve chain, priority and byte swapping
  814.     dwDMACSR0 = V3PBC_ReadRegDWord(hV3, V3PBC_DMA_LENGTH0 + dwChannelOffset) & 0xac00000;
  815.     V3PBC_WriteRegDWord(hV3, V3PBC_DMA_LENGTH0 + dwChannelOffset, (fRead ? 0 : BIT28) | BIT24 | dwBytes >> 2 | dwDMACSR0);
  816.     // if blocking then check BIT24 to wait for transfer to complete
  817.     if (fBlocking)
  818.         while (!V3PBC_DMAIsDone(hV3, dmaChannel));
  819.  
  820.     return TRUE;
  821. }
  822.  
  823. BOOL V3PBC_DMAIsDone(V3PBCHANDLE hV3, V3_DMA_CHANNEL dmaChannel)
  824. {
  825.     if (V3PBC_ReadRegDWord(hV3, V3PBC_DMA_LENGTH0 + dmaChannel*0x10) & BIT24)
  826.         return FALSE;
  827.     return TRUE;
  828. }
  829.  
  830.  
  831. //////////////////////////////////////////////////////////////////////////////
  832. // Card Reset
  833. //////////////////////////////////////////////////////////////////////////////
  834.  
  835. void V3PBC_PulseLocalReset(V3PBCHANDLE hV3, WORD wDelay)
  836. {
  837.     WORD System;
  838.  
  839.     // Unlock the system register
  840.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, SYSTEM_UNLOCK_TOKEN);
  841.  
  842.     // Assert the local reset line
  843.     System = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
  844.     V3PBC_WriteRegWord((V3PBCHANDLE) hV3, V3PBC_SYSTEM, (WORD) (System & ~SYSTEM_RST_OUT));
  845.  
  846.     // Lock the system register
  847.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (System | SYSTEM_LOCK));
  848.  
  849.     // Delay 
  850.     V3PBC_SleepMicro(hV3, ((DWORD) wDelay) * 1000);
  851.  
  852.     // Unlock the system register
  853.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM,  SYSTEM_UNLOCK_TOKEN);
  854.  
  855.     // De-assert the local reset line
  856.     System = V3PBC_ReadRegWord(hV3, (WORD) V3PBC_SYSTEM);
  857.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (System | SYSTEM_RST_OUT));
  858.  
  859.     // Lock the system register
  860.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (System | SYSTEM_LOCK));
  861. }
  862.  
  863. //////////////////////////////////////////////////////////////////////////////
  864. // Sleep (delay)
  865. //////////////////////////////////////////////////////////////////////////////
  866.  
  867. void V3PBC_SleepMicro(V3PBCHANDLE hV3, DWORD nMicro)
  868. {
  869.     WD_SLEEP sleep;
  870.     BZERO (sleep);
  871.     sleep.dwMicroSeconds = nMicro;
  872.     WD_Sleep( hV3->hWD, &sleep);
  873. }
  874.  
  875.  
  876. //////////////////////////////////////////////////////////////////////////////
  877. // EEPROM read/write
  878. //////////////////////////////////////////////////////////////////////////////
  879.  
  880. // Note: V3PBC_EEPROMInit should be called for each board.
  881. // This routine will force a stop condition on the I2C bus.
  882. // The clock and data lines will be left high and this routine will 
  883. // return after a half clock.
  884. void V3PBC_EEPROMInit(V3PBCHANDLE hV3)
  885. {
  886.     // Unlock the system register
  887.     I2C_UnLock(hV3);
  888.     
  889.     // Ensure that the I2C clock and data lines are in a known state 
  890.     I2C_Stop(hV3);
  891.     I2C_Delay(hV3);
  892.  
  893.     // Lock the system register 
  894.     I2C_Lock(hV3);
  895. }
  896.  
  897. // Parameters:
  898. // BYTE bSlaveAddr - 3 bit address of device been selected
  899. // BYTE bAddr - address of EEPROM location to be read from
  900. // BYTE bData - value to be written to EEPROM 
  901. //
  902. // Return:
  903. // BOOL fStatus - TRUE if read successful
  904. //
  905. // Description:
  906. // This routine writes a byte to the slave device's address specified.
  907. // This routine uses the Write Byte method from the Atmel documentation.
  908. BOOL V3PBC_EEPROMWrite(V3PBCHANDLE hV3, BYTE bSlaveAddr, BYTE bAddr, BYTE bData)
  909. {
  910.     BOOL fStatus = TRUE;
  911.  
  912.     // Set upper device address 
  913.     bSlaveAddr |= I2C_1010;
  914.  
  915.     // Unlock the system register
  916.     I2C_UnLock(hV3);
  917.  
  918.     // Send device Address and wait for Ack, bAddr is sent as a write 
  919.     if (!I2C_PollAckStart(hV3, bSlaveAddr, I2C_WRITE))
  920.         fStatus = FALSE;
  921.     else
  922.     {
  923.         // Send bAddr as the address to write 
  924.         if (!I2C_Write8(hV3, bAddr))
  925.             fStatus = FALSE;
  926.         else
  927.         {
  928.             // Send the value to write 
  929.             if (!I2C_Write8(hV3, bData))
  930.                 fStatus = FALSE;
  931.         }
  932.     }
  933.  
  934.     // Clean up the bus with a stop condition 
  935.     I2C_Stop(hV3);
  936.  
  937.     // Lock the system register 
  938.     I2C_Lock(hV3);
  939.     return fStatus;
  940. }
  941.  
  942. // Parameters:
  943. // BYTE bSlaveAddr - 3 bit address of device been selected
  944. // BYTE bAddr - address of EEPROM location to be read from
  945. // BYTE *bData - EEPROM data read back (pointer to data passed)
  946. //
  947. // Return:
  948. // BOOL fStatus - TRUE if read successful
  949. //
  950. // Description:
  951. // This routine reads back a byte from the slave device's address
  952. // specificed.  This routine uses the Random Read method in the Atmel
  953. // documentation.
  954. BOOL V3PBC_EEPROMRead(V3PBCHANDLE hV3, BYTE bSlaveAddr, BYTE bAddr, BYTE *bData)
  955. {
  956.     BOOL fStatus = TRUE;
  957.  
  958.     // Set upper device address 
  959.     bSlaveAddr |= I2C_1010;
  960.  
  961.     // Unlock the system register 
  962.     I2C_UnLock(hV3);
  963.  
  964.     // Send device Address and wait for Ack, bAddr is sent as a write 
  965.     if (!I2C_PollAckStart(hV3, bSlaveAddr, I2C_WRITE))
  966.         fStatus = FALSE;
  967.     else
  968.     {
  969.         // Send bAddr as the random address to be read 
  970.         if (!I2C_Write8(hV3, bAddr))
  971.             fStatus = FALSE;
  972.         else
  973.         {
  974.             // Send a START condition and device address this time as read 
  975.             if (!I2C_StartSlave(hV3, bSlaveAddr, I2C_READ))
  976.                 fStatus = FALSE;
  977.             else
  978.                 // read the date back from EEPROM 
  979.                 *bData = I2C_Read8(hV3);
  980.         }
  981.     }
  982.  
  983.     // clean up bus with a NaK and Stop condition 
  984.     I2C_NoAck(hV3);
  985.     I2C_Stop(hV3);
  986.  
  987.     // Lock the system register 
  988.     I2C_Lock(hV3);
  989.     return fStatus;
  990. }
  991.  
  992. // Parameters:
  993. // BYTE bAddr - 3 bit address of device been selected
  994. // bit ReadBit - Set if command is to be a read, reset if command is a write 
  995. //
  996. // Return:
  997. // TRUE    - read was successful
  998. // FALSE   - if negative acknowledge was received
  999. //
  1000. // Description:
  1001. // All commands are preceded by the start condition, which is a high
  1002. // to low transition of SDA when SCL is high.  All I2C devices
  1003. // continuously monitor the SDA and SCL lines for the start condition 
  1004. // and will not respond to any command until this condition has been met.
  1005. //
  1006. // Once a device detects that it is being addressed it outputs an 
  1007. // acknowledge on the SDA line.  Depending on the state of the read/write 
  1008. // bit, the device will execute a read or write operation.
  1009. //
  1010. // +-----+-----+-----+-----+-----+-----+-----+-----+
  1011. // | SA6 | SA5 | SA4 | SA3 | SA2 | SA1 | SA0 | R/W |
  1012. // +-----+-----+-----+-----+-----+-----+-----+-----+
  1013. //                                              |--- 1=read, 0=write
  1014. BOOL I2C_StartSlave(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit)
  1015. {
  1016.     I2C_SCL(hV3, TRUE);
  1017.     I2C_Delay(hV3);
  1018.     I2C_SDA(hV3, FALSE);
  1019.     I2C_Delay(hV3);
  1020.     I2C_SCL(hV3, FALSE);
  1021.     I2C_Delay(hV3);
  1022.     return I2C_Write8(hV3, (BYTE) (bAddr<<1 | ReadBit));
  1023. }
  1024.  
  1025. // Parameters:
  1026. // V3PBCHANDLE hV3 - Handle to PBC32 data structure.
  1027. // BYTE bAddr - 3 bit address of device been selected
  1028. // bit ReadBit - Set if command is to be a read, reset if command is a write 
  1029. //
  1030. // Return:
  1031. // FALSE    - device is not responding (retried out)
  1032. // TRUE     - read was successful
  1033. //
  1034. // Description:
  1035. // This routine checks the status of the device being written to by 
  1036. // issuing a start condition followed by check for ACK.  If the slave
  1037. // device is unable to communicate, the write command will not be
  1038. // acknowledged and we should wait.  This routine will try I2C_RETRY times for 
  1039. // an ACK before returning a I2C_BUSY indication.
  1040. BOOL I2C_PollAckStart(V3PBCHANDLE hV3, BYTE bAddr, BYTE ReadBit)
  1041. {
  1042.     BYTE bTries = I2C_RETRY;
  1043.     do
  1044.     {
  1045.         I2C_SDA(hV3, FALSE);
  1046.         I2C_Delay(hV3);
  1047.         I2C_SCL(hV3, FALSE);
  1048.         I2C_Delay(hV3);
  1049.         if (I2C_Write8(hV3, (BYTE) (bAddr<<1 | ReadBit)))
  1050.             return TRUE;
  1051.     }
  1052.     while(bTries--);
  1053.     return FALSE;
  1054. }
  1055.  
  1056. // Reads eight bits from the I2C bus.
  1057. // Return: BYTE bData - returns a byte of data 
  1058. BYTE I2C_Read8(V3PBCHANDLE hV3)
  1059. {
  1060.     BYTE i, bData=0;
  1061.  
  1062.     I2C_SDA(hV3, TRUE);
  1063.     for (i=8; i; --i )
  1064.     {
  1065.         I2C_SCL(hV3, TRUE);
  1066.         I2C_Delay(hV3);
  1067.         bData = (bData<<1) | I2C_SDAIn(hV3);
  1068.         I2C_SCL(hV3, FALSE);
  1069.         I2C_Delay(hV3);
  1070.     }
  1071.     return bData;
  1072. }
  1073.  
  1074. // Return:
  1075. // TRUE  - OK
  1076. // FALSE - BUSY or negative acknowledge
  1077. //
  1078. // Description:
  1079. // This routine writes out all 8 bits of data out to the I2C bus.  After 
  1080. // writing out the data, the routine reads the ACK/NACK response back and
  1081. // returns it to the caller.
  1082. BOOL I2C_Write8(V3PBCHANDLE hV3,BYTE bData)
  1083. {
  1084.     BYTE bAck;
  1085.     BYTE i;
  1086.     for (i=0x80; i; i >>=1 )
  1087.     {
  1088.         I2C_SDA(hV3, (i & bData) ? TRUE : FALSE);
  1089.         I2C_SCL(hV3, TRUE);
  1090.         I2C_Delay(hV3);
  1091.         I2C_SCL(hV3, FALSE);
  1092.         I2C_Delay(hV3);
  1093.     }
  1094.     I2C_SDA(hV3, TRUE);
  1095.     I2C_SCL(hV3, TRUE);
  1096.     bAck= I2C_SDAIn(hV3);
  1097.     I2C_Delay(hV3);
  1098.     I2C_SCL(hV3, FALSE);
  1099.     I2C_Delay(hV3);
  1100.  
  1101.     return bAck==0;
  1102. }
  1103.  
  1104. // All communications must be terminated by a stop condition which
  1105. // is a low to high transition of SDA while SCL is high.  A stop 
  1106. // condition can only be issued after the transmitting device has 
  1107. // released the bus.
  1108. void I2C_Stop(V3PBCHANDLE hV3)
  1109. {
  1110.     I2C_SDA(hV3, FALSE);
  1111.     I2C_Delay(hV3);
  1112.     I2C_SCL(hV3, TRUE);
  1113.     I2C_Delay(hV3);
  1114.     I2C_SDA(hV3, TRUE);
  1115. }
  1116.  
  1117. // The No-Acknowledge is a software convention used to indicate
  1118. // unsucessful data transfers.  The transmitting device, either 
  1119. // master or slave, will release the bus after transmitting 
  1120. // eight bits.  During the ninth clock cycle the receiver will 
  1121. // pull the SDA line high to indicate that it did not received the 
  1122. // eight bits of data.
  1123. void I2C_NoAck(V3PBCHANDLE hV3)
  1124. {
  1125.     I2C_SDA(hV3, TRUE);
  1126.     I2C_Delay(hV3);
  1127.     I2C_SCL(hV3, TRUE);
  1128.     I2C_Delay(hV3);
  1129.     I2C_SCL(hV3, FALSE);
  1130. }
  1131.  
  1132. // Acknowledge is a software convention used to indicate
  1133. // sucessful data transfers.  The transmitting device, either 
  1134. // master or slave, will release the bus after transmitting 
  1135. // eight bits.  During the ninth clock cycle the receiver will 
  1136. // pull the SDA line low to acknowledge that it received the 
  1137. // eight bits of data.
  1138. void I2C_Ack(V3PBCHANDLE hV3)
  1139. {
  1140.     I2C_SDA(hV3, FALSE);
  1141.     I2C_Delay(hV3);
  1142.     I2C_SCL(hV3, TRUE);
  1143.     I2C_Delay(hV3);
  1144.     I2C_SCL(hV3, FALSE);
  1145. }
  1146.  
  1147. // This routine returns the state of the Serial Data line
  1148. // Return: BYTE bData - state of the Serial Data line
  1149. BYTE I2C_SDAIn(V3PBCHANDLE hV3)
  1150. {
  1151.     WORD wSystem;
  1152.  
  1153.     wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
  1154.     return ((wSystem & SYSTEM_SDA_IN) >> SYSTEM_SDA_IN_SHIFT);
  1155. }
  1156.  
  1157. // This routine sets the Serial Data line to the desired state.
  1158. //
  1159. // Parameters: 
  1160. // BOOL fHigh - what state the SDA is to be set to
  1161. void I2C_SDA(V3PBCHANDLE hV3, BOOL fHigh)
  1162. {
  1163.     WORD wSystem;
  1164.  
  1165.     wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
  1166.     if(fHigh)
  1167.         wSystem |= SYSTEM_SDA_OUT;
  1168.     else
  1169.         wSystem &= ~SYSTEM_SDA_OUT;
  1170.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, wSystem);
  1171. }
  1172.  
  1173. // This routine sets the Serial Clock line to the desired state.
  1174. //
  1175. // Parameters: 
  1176. // BOOL fHigh - what state the SCL is to be set to
  1177. void I2C_SCL(V3PBCHANDLE hV3, BOOL fHigh)
  1178. {
  1179.     WORD wSystem;
  1180.  
  1181.     wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
  1182.     if(fHigh)
  1183.         wSystem |= SYSTEM_SCL;
  1184.     else
  1185.         wSystem &= ~SYSTEM_SCL;
  1186.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, wSystem);
  1187. }
  1188.  
  1189. // This routine disables the Serial Clock pin, and sets the sytem
  1190. // lock bit.
  1191. void I2C_Lock(V3PBCHANDLE hV3)
  1192. {
  1193.     WORD wSystem;
  1194.  
  1195.     wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
  1196.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (wSystem & ~SYSTEM_SPROM_EN));
  1197.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (wSystem | SYSTEM_LOCK));
  1198. }
  1199.  
  1200. // This routine enable the sytem register for writting, and enables
  1201. // the Serial Clock output pin.
  1202. void I2C_UnLock(V3PBCHANDLE hV3)
  1203. {
  1204.     WORD wSystem;
  1205.  
  1206.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, SYSTEM_UNLOCK_TOKEN);
  1207.     wSystem = V3PBC_ReadRegWord(hV3, V3PBC_SYSTEM);
  1208.     V3PBC_WriteRegWord(hV3, V3PBC_SYSTEM, (WORD) (wSystem |SYSTEM_SPROM_EN));
  1209. }
  1210.  
  1211. // This routine inserts delay.  0.005 Milliseconds is enough time
  1212. void I2C_Delay(V3PBCHANDLE hV3)
  1213. {
  1214.     V3PBC_SleepMicro(hV3, 5);
  1215. }
  1216.